import java.util.HashMap;

import pusher.Grid;
import structural.Constants;

public class PusherGame {

	private Grid grid;
	private int plannedMove=0;
	private boolean isWhite;
	private HashMap<Grid, Integer> transpositionTable = new HashMap<Grid,Integer>();

	// Constructeur qui permet l'initialisation d'une game pré-jouée
	public PusherGame(String[] grid) {
		this.grid = new Grid(grid);
	}
	
	public PusherGame() {
		
	}

	public int getPlannedMove() {
		return plannedMove;
	}

	public void setColor(boolean white) {
		isWhite = white;
		System.out.println(isWhite);
	}

	public void displayGrid() {
		grid.display();
	}

	// format " A1 - A2"
	public boolean move(String move) {
		int x = '8' - move.charAt(2);
		int y = move.charAt(1) - 'A';
		boolean valid = false;

		int pos = x * 8 + y;

		int dest = move.charAt(6) - 'A';
		
		if (Math.abs(('8' - move.charAt(7)) - x) == 1) {
			if (dest == y-1) {
				valid = grid.leftDiagonalMove(pos);
			} else if (dest == y) {
				valid = grid.frontMove(pos);
			} else if(dest == y+1){
				valid = grid.rightDiagonalMove(pos);
			}
		}
		
		if(valid){
			plannedMove = 0;
		}
		if(!valid){
			System.out.println();
		}
		return valid;
	}

	public int generate(Grid position, boolean white, boolean max, int alpha,
			int beta, int index) {
		// if (index == 1)
		// plannedMove = root.getMove();

		int score;
		int alphaActuel = Constants.BASE_ALPHA;
		int betaActuel = Constants.BASE_BETA;
		Grid actualGrid = position;
		if(index == 1 && plannedMove == 0){
			plannedMove = position.getLastMove();
		}
		if(max){
			score = alphaActuel;
		}else{
			score = betaActuel;
		}

		Grid movingGrid = actualGrid.clone();
		if (white) {
			// white loop
			int wPiece = actualGrid.getFirstPieceAfter(Constants.WHITE, -1);
			while (wPiece != -1 && !Main.timeOut) {

				if (movingGrid.rightDiagonalMove(wPiece)) {

					if ((wPiece / 8) == 1 || index >= Constants.MAX_TREE_LEVEL) {
						if (max) {
							score = Math.max(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						} else {
							score = Math.min(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						}
					} else {
						if (max) {
							
							score = Math.max(score, generate(movingGrid, !white,
									false, Math.max(alphaActuel, alpha), beta,
									index + 1));							
						} else {

							score = Math.min(score, generate(movingGrid, !white,
									true, alpha, Math.min(beta, betaActuel),
									index + 1));							
						}

					}
					if(max){
						if (index == 0 && score > alphaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						alphaActuel = Math.max(alphaActuel, score);
						
						if (alphaActuel >= beta) {
							return alphaActuel;
						}
					}else{
						if (index == 0 && score < betaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						betaActuel = Math.min(betaActuel, score);
						if (betaActuel <= alpha) {
							return betaActuel;
						}
					}

					movingGrid.copyGrid(actualGrid);
				}				

				if (movingGrid.leftDiagonalMove(wPiece)) {

					if ((wPiece / 8) == 1 || index >= Constants.MAX_TREE_LEVEL) {
						if (max) {
							score = Math.max(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						} else {
							score = Math.min(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						}
					} else {
						if (max) {

							score = Math.max(score, generate(movingGrid, !white,
									false, Math.max(alphaActuel, alpha), beta,
									index + 1));
							
						} else {

							score = Math.min(score, generate(movingGrid, !white,
									true, alpha, Math.min(beta, betaActuel),
									index + 1));
							
						}

					}
					if(max){
						if (index == 0 && score > alphaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						alphaActuel = Math.max(alphaActuel, score);
						
						if (alphaActuel >= beta) {
							return alphaActuel;
						}
					}else{
						if (index == 0 && score < betaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						betaActuel = Math.min(betaActuel, score);
						if (betaActuel <= alpha) {
							return betaActuel;
						}
					}

					movingGrid.copyGrid(actualGrid);
				}
				
				if (movingGrid.frontMove(wPiece)) {

					if ((wPiece / 8) == 1 || index >= Constants.MAX_TREE_LEVEL) {
						if (max) {
							score = Math.max(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						} else {
							score = Math.min(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						}
					} else {
						if (max) {

							score = Math.max(score, generate(movingGrid, !white,
									false, Math.max(alphaActuel, alpha), beta,
									index + 1));
							
						} else {

							score = Math.min(score, generate(movingGrid, !white,
									true, alpha, Math.min(beta, betaActuel),
									index + 1));
							
						}

					}
					if(max){
						if (index == 0 && score > alphaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						alphaActuel = Math.max(alphaActuel, score);
						
						if (alphaActuel >= beta) {
							return alphaActuel;
						}
					}else{
						if (index == 0 && score < betaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						betaActuel = Math.min(betaActuel, score);
						if (betaActuel <= alpha) {
							return betaActuel;
						}
					}

					movingGrid.copyGrid(actualGrid);
				}
				
				wPiece = actualGrid
						.getFirstPieceAfter(Constants.WHITE, wPiece);

			}
			if (max) {
				return alphaActuel;
			} else {
				return betaActuel;
			}
		} else {
			// black loop
			int bPiece = actualGrid.getFirstPieceBefore(Constants.BLACK, 64);
			while (bPiece != -1 && !Main.timeOut) {

				if (movingGrid.leftDiagonalMove(bPiece)) {
					if ((bPiece / 8) == 6 || index >= Constants.MAX_TREE_LEVEL) {
						if (max) {
							score = Math.max(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						} else {
							score = Math.min(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						}
					} else {
						if (max) {

							score = Math.max(score, generate(movingGrid, !white,
									false, Math.max(alphaActuel, alpha), beta,
									index + 1));

							
							
						} else {

							score = Math.min(score, generate(movingGrid, !white,
									true, alpha, Math.min(beta, betaActuel),
									index + 1));

							
							
						}

					}
					if(max){
						if (index == 0 && score > alphaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						alphaActuel = Math.max(alphaActuel, score);
						
						if (alphaActuel >= beta) {
							return alphaActuel;
						}
					}else{
						if (index == 0 && score < betaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						betaActuel = Math.min(betaActuel, score);
						if (betaActuel <= alpha) {
							return betaActuel;
						}
					}

					movingGrid.copyGrid(actualGrid);
				}				

				if (movingGrid.rightDiagonalMove(bPiece)) {
					if ((bPiece / 8) == 6 || index >= Constants.MAX_TREE_LEVEL) {
						if (max) {
							score = Math.max(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						} else {
							score = Math.min(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
						}
					} else {
						if (max) {

							score = Math.max(score, generate(movingGrid, !white,
									false, Math.max(alphaActuel, alpha), beta,
									index + 1));							
							
						} else {

							score = Math.min(score, generate(movingGrid, !white,
									true, alpha, Math.min(beta, betaActuel),
									index + 1));
							
						}

					}
					if(max){
						if (index == 0 && score > alphaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						alphaActuel = Math.max(alphaActuel, score);
						
						if (alphaActuel >= beta) {
							return alphaActuel;
						}
					}else{
						if (index == 0 && score < betaActuel) {
							plannedMove = movingGrid.getLastMove();
						}
						
						betaActuel = Math.min(betaActuel, score);
						if (betaActuel <= alpha) {
							return betaActuel;
						}
					}
					
					if (movingGrid.frontMove(bPiece)) {
						if ((bPiece / 8) == 6 || index >= Constants.MAX_TREE_LEVEL) {
							if (max) {
								score = Math.max(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
							} else {
								score = Math.min(score, evaluate(movingGrid) * Constants.MAX_TREE_LEVEL - index);
							}
						} else {
							if (max) {

								score = Math.max(score, generate(movingGrid, !white,
										false, Math.max(alphaActuel, alpha), beta,
										index + 1));

								
								
							} else {

								score = Math.min(score, generate(movingGrid, !white,
										true, alpha, Math.min(beta, betaActuel),
										index + 1));

								
								
							}

						}
						if(max){
							if (index == 0 && score > alphaActuel) {
								plannedMove = movingGrid.getLastMove();
							}
							
							alphaActuel = Math.max(alphaActuel, score);
							
							if (alphaActuel >= beta) {
								return alphaActuel;
							}
						}else{
							if (index == 0 && score < betaActuel) {
								plannedMove = movingGrid.getLastMove();
							}
							
							betaActuel = Math.min(betaActuel, score);
							if (betaActuel <= alpha) {
								return betaActuel;
							}
						}

						movingGrid.copyGrid(actualGrid);
					}

					movingGrid.copyGrid(actualGrid);
				}
				bPiece = actualGrid.getFirstPieceBefore(Constants.BLACK, bPiece);

			}
			if (max) {
				return alphaActuel;
			} else {
				return betaActuel;
			}
		}

	}

	private int evaluate(Grid cg) {
		int value = 0;

		for (int i = 0; i < 64; i++) {
			if (!cg.isEmpty(i)) {
				int row = i / 8;
				int type = cg.getType(i);
				if (isWhite == (cg.getColor(i) == Constants.WHITE)) {
					// true if same color
					value += type;
					if (isWhite) {
						value += (7 - row)*type;
						if (row == 0)
							value += 99999;
					} else {
						value += row*type;
						if (row == 7)
							value += 99999;
					}
				} else {
					value -= type;
					
					if (isWhite) {
						value -= row*type;
						if (row == 7)
							value -= 99999;
					} else {
						value -= (7 - row)*type;
						if (row == 0)
							value -= 99999;
					}
				}
			}
		}

		return value;
	}

	public Grid getGrid() {
		return grid;
	}
}
